package com.yehebl.orm.data.mysql;

import com.yehebl.orm.data.common.IDao;
import com.yehebl.orm.data.common.ISqlBuild;
import com.yehebl.orm.data.common.dto.Page;
import com.yehebl.orm.data.common.dto.ResultObject;
import com.yehebl.orm.data.common.dto.SimplePage;
import com.yehebl.orm.data.lambda.PropertyFun;
import com.yehebl.orm.dto.ClassInfo;
import com.yehebl.orm.exception.ClassNotEntityException;
import com.yehebl.orm.manager.ReadClassManager;
import com.yehebl.orm.util.LambdaUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * sql 构建器
 *
 * @author Administrator
 */
public class MySqlSqlBuild implements ISqlBuild {

    private final IDao dao;
    private final StringBuilder sqlBuild = new StringBuilder();

    private boolean isSelect = false;

    private final List<Object> params = new ArrayList<>();

    public MySqlSqlBuild(IDao dao) {
        this.dao = dao;
    }

    protected ClassInfo getClassInfo(Class<?> clazz) {
        ClassInfo classInfo = ReadClassManager.map.get(clazz.getName());
        if (classInfo == null) {
            throw new ClassNotEntityException(clazz);
        }
        return classInfo;
    }

    @Override
    public <T> ISqlBuild select(Class<T> clazz, String alias) {
        final ClassInfo ci = getClassInfo(clazz);
        String sql = MySqlSqlManager.getColumn(ci, alias);
        if (!isSelect) {
            isSelect = true;
            sqlBuild.append("select ").append(sql);
        } else {
            sqlBuild.append(",").append(sql);
        }
        return this;
    }

    @Override
    public <T> ISqlBuild select(Class<T> clazz, String alias, String objectName) {
        final ClassInfo ci = getClassInfo(clazz);
        String sql = MySqlSqlManager.getColumn(ci, alias, objectName);
        if (!isSelect) {
            isSelect = true;
            sqlBuild.append("select ").append(sql);
        } else {
            sqlBuild.append(",").append(sql);
        }
        return this;
    }

    @Override
    public <T, R> ISqlBuild select(Class<T> clazz, String alias, PropertyFun<T, R> column) {
        final ClassInfo ci = getClassInfo(clazz);
        String sql = MySqlSqlManager.getColumn(ci, alias, LambdaUtil.getPropertyName(column));
        if (!isSelect) {
            isSelect = true;
            sqlBuild.append("select ").append(sql);
        } else {
            sqlBuild.append(",").append(sql);
        }
        return this;
    }

    @Override
    public <T> ISqlBuild from(Class<T> clazz, String alias) {
        final ClassInfo ci = getClassInfo(clazz);
        this.join("from " + ci.getTableName() + " " + alias);
        return this;
    }

    @Override
    public <T> ISqlBuild from(Class<T> clazz) {
        final ClassInfo ci = getClassInfo(clazz);
        this.join("from " + ci.getTableName());
        return this;
    }

    @Override
    public <T> ISqlBuild left(Class<T> clazz, String alias) {
        final ClassInfo ci = getClassInfo(clazz);
        this.join("left join " + ci.getTableName() + " " + alias);
        return this;
    }

    @Override
    public <T> ISqlBuild right(Class<T> clazz, String alias) {
        final ClassInfo ci = getClassInfo(clazz);
        this.join("right join " + ci.getTableName() + " " + alias);
        return this;
    }

    @Override
    public <T> ISqlBuild inner(Class<T> clazz, String alias) {
        final ClassInfo ci = getClassInfo(clazz);
        this.join("inner join " + ci.getTableName() + " " + alias);
        return this;
    }

    @Override
    public <T> ISqlBuild on(String sql) {
        this.join("on " + sql);
        return this;
    }

    @Override
    public <T> ISqlBuild where(String sql) {
        this.join("where " + sql);
        return this;
    }

    @Override
    public <T> ISqlBuild where(String sql, Object... objs) {
        this.join("where " + sql);
		Collections.addAll(this.params,objs);
        return this;
    }

    @Override
    public String toString() {
        return sqlBuild.toString();
    }

    @Override
    public <T> ISqlBuild select(Class<T> clazz) {
        final ClassInfo ci = getClassInfo(clazz);
        String sql = MySqlSqlManager.getColumn(ci);
        if (!isSelect) {
            isSelect = true;
            sqlBuild.append("select ").append(sql);
        } else {
            sqlBuild.append(",").append(sql);
        }
        return this;
    }

    @Override
    public ISqlBuild join(String sql) {
        sqlBuild.append(" ").append(sql);
        return this;
    }

    @Override
    public ISqlBuild join(String sql, Object... objs) {
		Collections.addAll(this.params,objs);
        sqlBuild.append(" ").append(sql);
        return this;
    }

    @Override
    public ISqlBuild trueJoin(boolean flag, String sql) {
        if (flag) {
            sqlBuild.append(" ").append(sql);
        }
        return this;
    }

    @Override
    public ISqlBuild trueJoin(boolean flag, String sql, Object... objs) {
        if (flag) {
            sqlBuild.append(" ").append(sql);
            Collections.addAll(this.params, objs);
        }
        return this;
    }

    /**
     * 拼接in的sql
     */
    @Override
    public ISqlBuild trueJoinIn(boolean flag, String sql, Object... objs) {
        if (flag) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < objs.length; i++) {
                if (i + 1 == objs.length) {
                    sb.append("?");
                } else {
                    sb.append("?,");
                }
                this.params.add(objs[i]);
            }
            sqlBuild.append(" ").append(sql.replace("?", sb.toString()));
        }
        return this;
    }

    @Override
    public ISqlBuild joinIn(String sql, Object... objs) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < objs.length; i++) {
            if (i + 1 == objs.length) {
                sb.append("?");
            } else {
                sb.append("?,");
            }
            this.params.add(objs[i]);
        }
        sqlBuild.append(" ").append(sql.replace("?", sb.toString()));
        return this;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return this.dao.getBySql(sqlBuild.toString(), clazz, this.params.toArray());
    }

    @Override
    public <T> List<T> find(Class<T> clazz) {
        return this.dao.findBySql(sqlBuild.toString(), clazz, this.params.toArray());
    }

    @Override
    public Object get() {
        return this.dao.getObjectBySql(sqlBuild.toString(), this.params.toArray());
    }

    @Override
    public ResultObject getResultObjectBySql() {
        return this.dao.getResultObjectBySql(sqlBuild.toString(), this.params.toArray());
    }

    @Override
    public <T> Page<T> findPageBySql(int page, int size, Class<T> clazz) {
        return this.dao.findPageBySql(sqlBuild.toString(), page, size, clazz, this.params.toArray());
    }

    @Override
    public <T> Page<T> findPageBySql(int page, int size,int pageType, Class<T> clazz) {
        return this.dao.findPageBySql(sqlBuild.toString(), page, size,pageType, clazz, this.params.toArray());
    }

    @Override
    public <T> SimplePage<T> findSimplePageBySql(int page, int size, Class<T> clazz) {
        return this.dao.findSimplePageBySql(sqlBuild.toString(), page, size, clazz, this.params.toArray());
    }

}
